<?php                      
if( !defined('BASE') ) exit('Access Denied!');

/**
 * Obullo Framework (c) 2009.
 *
 * PHP5 Minimalist software for PHP 5.2.4 or newer
 *
 * @package         Obullo  
 * @author          Obullo.com  
 * @subpackage      Base.libraries        
 * @copyright       Copyright (c) 2009 Ersin Güvenç.
 * @license         http://www.opensource.org/licenses/gpl-3.0.html GPL  
 * @filesource
 */ 
 
/**
 * Loader Class (Obullo Loader Pattern) (c) 2009 - 2010
 *
 * Load obullo library,model,view.. files
 *
 * @package         Obullo 
 * @subpackage      Base.libraries     
 * @category        Loader
 * @version         0.1
 * @version         0.2 added model and load db function
 * @version         0.3 added static properties for database(),model(),library()
 *                      added load_DB variable (Model database load on/off).
 *                      added asn_to_models(),helper(),dir()
 * @version         0.4 renamed static functions ob::instance(),ob::register()..
 *                  added static param to library func.Added __construct support
 *                  to library.
 * @version         0.5 changed directory structure added $GLOBALS['d'] (directory)
 * @version         0.6 loader::database() and libraries _asn_lib() instanceof problem fixed.
 * @version         0.7 added base(), _library(), base_helper(), base_view() functions. 
 * @version         0.8 added js(), base_js(), script(), base_script() functions.Removed dir() function.
 * @version         0.9 added __autoloader() functionality, moved __autoloader to User.php
 * @version         1.0 added loader::css(), loader::base_css()
 * @version         1.1 renamed base "libraries" folder as base
 * @version         1.2 added loader::script(, $compress = true) functionality, added views/base_views folder
 * @version         1.3 added js compression, removed Library class functions
 * @version         1.4 removed compress, moved all view functions to Content class.
 */

Class LoaderException extends CommonException {}

require(APP.'user'.DS.'User_Controller'.EXT);
                
Class loader extends User_Controller {  
    
    /**
    * Obullo Models
    * Store all loaded Models
    * 
    * @var array
    */
    public $_mods = array();
    
    /**
    * Obullo Libraries
    * Store all loaded Libraries
    * 
    * @var array
    */
    public $_libs = array();
   
    /**
    * loader::lib();
    * 
    * load app libraries from /directories folder.
    * 
    * @param    mixed $class
    * @param    mixed $static_or_params
    * @return   self::_library()
    */
    public function lib($class, $static_or_params = NULL)
    {          
        $this->_library($class, $static_or_params, FALSE, '', 'directory'); 
    }
    
    /**
    * loader::app_lib();
    * 
    * load app libraries from /application folder.
    * 
    * @param    mixed $class
    * @param    mixed $static_or_params
    * @return   self::_library()
    */
    public function app_lib($class, $static_or_params = NULL)
    {          
        $this->_library($class, $static_or_params); 
    }
    
    /**
    * loader::base_lib();
    * 
    * load base libraries from /base folder.
    * 
    * @param    mixed $class
    * @param    mixed $static_or_params
    * @return   self::_library()
    */
    public function base_lib($class, $static_or_params = NULL)
    {             
        $this->_library($class, $static_or_params, TRUE); 
    }
    
    /**
    * Obullo Library Pattern (c) 2009
    * 
    * Load user or system classes
    * from application/libraries or base/libraries
    * directories.
    * 
    * @author   Ersin Güvenç
    * @author   you..
    * @param    string $class class name
    * @param    mixed $static instantiate switch load class not declare it 
    *                      Booelan or Array (provide __CONSTRUCT params)
    * @version  0.1
    * @version  0.2  added register_static functions
    * @return   void
    */
    private function _library($class, $static_or_params = NULL, $base = FALSE, $object_name = '', $lib_dir = '')
    {
        if($class == '')
        return FALSE;
        
        if($object_name != '') $class = $object_name; 
        
        if($static_or_params === TRUE)
        {   
            // if someone want to load static class
            // like Myclass::mymethod, include it.
            register_static($class);
            return;
        }

        // Instantiate the Super Object.        
        $OB = obullo::instance();
        
        // Lazy Loading
        if (class_exists($class) AND isset($OB->$class) AND is_object($OB->$class))
        return FALSE;  
        
        switch ($base)
        {
           case FALSE:
             $OB->$class = register($class, $static_or_params, $lib_dir); 
             break;
             
           case TRUE:
             $OB->$class = base_register($class, $static_or_params); 
             break;
        }
        
        if($OB->$class === NULL)
        throw new LoaderException('Unable to locate the library file: '.$class);
    
        // assign all libraries to all models
        // support for loader::libray() func. inside from
        // public model functions
        self::asn_to_models();
    
        $OB->_libs[$class] = $class;    
    }
    
    /**
    * loader::view();
    * 
    * Load view files
    * Don't declare this func as static
    * because of ability to use $this
    *  
    * @author   Ersin Güvenç
    * @author   you..
    * @param    string $filename filename
    * @param    array $data view data
    * @version  0.1
    * @version  0.2 Changed $GLOBALS['c'] as $GLOBALS['d']
    * @version  0.3 Changed string param default as true
    * @return   self::_view()
    */
    public function view($filename, $data = array(), $string = TRUE)
    {               
        return $this->content->view(DIR . $GLOBALS['d']. DS . 'views' . DS, $filename, $data, $string);
    }
    
    /**
    * loader::app_view();
    * 
    * load top html page for every views 
    * Base view file comes from 
    * base/views directory
    * 
    * @param    string $filename                   
    * @param    array $data
    * @version  0.1
    * @version  0.2 Removed string param
    * @return   self::_view()
    */
    public function app_view($filename, $data = array(), $string = FALSE)
    {
        return $this->content->view(APP .'views'. DS, $filename, $data, $string); 
    }
       
    /**
    * loader::app_model();
    * 
    * @author   Ersin Güvenç
    * @param    string $model
    * @return   void
    */
    public function app_model($model)
    {
        $this->_model(APP.'models'.DS.strtolower($model).EXT, strtolower($model));
    }
       
    /**
    * loader::model();
    * Obullo Model Loader
    * 
    * @author    Ersin Güvenç
    * @author    you..
    * @copyright obullo.com
    * @param     string $model
    * @version   0.1
    * @version   0.2 added directory support
    * @version   0.3 changed $GLOBALS['c'] as $GLOBALS['d']
    * @version   0.4 removed old current path support added
    *                new model directory structure support 
    * @version   0.5 added multiple load support
    * @return    void
    */
    public function model($model)
    {        
        $model_name = strtolower($model);
        
        // Controller directory support for model
        // if user provide path separator like this  loader::model(blog/model_blog)
        
        if (strpos($model_name, '/') > 0)
        {
            $paths = explode('/',$model_name); // path[0] = controller name
            $model_name = array_pop($paths);
            $path  = implode('/',$paths).'/';
            
            $file = DIR.$path.$model_name.EXT;
        } 
        else
        {
            // Load current controller model
            $file = DIR.$GLOBALS['d'].DS.'models'.DS.$model_name.EXT;
        }
        
        $this->_model($file, $model_name);
    }
    
    /**
    * Load model
    * 
    * @param   string $file
    * @param   string $model_name
    */
    private function _model($file, $model_name)
    {
        if ( ! file_exists($file))
        {
            throw new LoaderException('Unable to locate the model: '.$model_name);
        }
        
        $OB = obullo::instance();  
        
        if (isset($OB->$model_name) AND is_object($OB->$model_name))
        {
            throw new LoaderException('This model already loaded before: '.$model_name);
        }
        
        require($file);
        $model = ucfirst($model_name);   

        if( ! class_exists($model_name))
        {
            throw new LoaderException('Model name is not correct in file: '.$model_name);
        }
        
        $OB->$model_name = new $model();    //register($class); we don't need it   

        // assign all loaded libraries inside to current model
        // loader::library() support for Model_x { function __construct() { loader::library() }}
        $OB->$model_name->_asn_lib();
        
        // store loaded obullo models
        $OB->_mods[$model_name] = $model_name;  
    }

    /**
    * loader::database();
    * 
    * Database load.
    * This function loads the database for jus current
    * Controller, not models, not libraries etc.. 
    * 
    * @author   Ersin Güvenç
    * @author   you..
    * @param    mixed $db_name for manual connection
    * @param    boolean $ac active record switch
    * @version  0.1
    * @version  0.2 multiple models load::database function support.
    *               Loading model inside again model bug fixed.
    * @version  0.3 Deprecated debug_backtrace(); function
    *               added asn_to_libraries();, asn_to_models();
    * @version  0.4 added DBFactory() Actice Record Switch
    *               added $ac param.
    * 
    * @version  0.5 added $db_name param for multiple connection
    * @return   void
    */
    public function database($db_name = '', $ac = TRUE)
    {
        $OB = obullo::instance();
        
        if($db_name == '')
        {
            if (class_exists('DB') AND isset($OB->db) AND is_object($OB->db))
            return FALSE;
            
        } elseif(is_string($db_name)) 
        {
            if (class_exists('DB') AND isset($OB->{$db_name}) AND is_object($OB->{$db_name}))
            return FALSE;
        
        } elseif(is_array($db_name))
        {
            if (class_exists('DB') AND isset($OB->{$db_name['variable']}) AND is_object($OB->{$db_name['variable']}))
            return FALSE;
        }
        
        if(! class_exists('DBFactory'))
        require(BASE.'database'.DS.'DBFactory'.EXT);
        
        $factory = new DBFactory($db_name);
        
        // Db Active Record switch ...
        $factory->Active_Record($ac);
    
        if($db_name == '')
        {
            $OB->db = $factory->Connect();
        
        } elseif(is_string($db_name))
        {
            $OB->{$db_name} = $factory->Connect();
        
        } elseif(is_array($db_name))
        {            
            $OB->{$db_name['variable']} = $factory->Connect($db_name);
        }

        // Assign db object to all models
        self::asn_to_models(); 
    }        

    /**
    * loader::app_helper();
    * 
    * @param    string $helper
    */
    public function app_helper($helper)
    {
        if(file_exists(APP.'helpers'.DS.$helper.EXT))
        {
            include(APP.'helpers'.DS.$helper.EXT);
            return;    
        }
        
        throw new LoaderException('Unable to locate the application helper: '.$helper.EXT); 
    }
    
    /**
    * loader::helper();
    * 
    * We have three helper directory
    *   o Base/helpers  : /base helpers
    *   o App/helpers   : /application helpers
    *   o Directories/helpers: /directiories/$directory helpers
    * 
    * @author   Ersin Güvenç
    * @author   you..
    * @param    string $helper
    * @version  0.1
    * @version  0.2 changed $GLOBALS['c'] as $GLOBALS['d']
    * @version  0.3 changed base helper functionality as base_helper()
    * @version  0.4 added multiple helper load functionality
    * @return   void
    */
    public static function helper($helper)
    { 
        if (strpos($helper, '/') > 0)
        {
            $paths = explode('/',$helper);  // path[0] = controller name
            $helper_name = array_pop($paths);
            $path  = implode('/',$paths).'/';
            
            if(file_exists(DIR.$path.$helper_name.EXT))
            {
                include(DIR.$path.$helper_name.EXT);
                return;
            } 
            
            throw new LoaderException('Unable to locate the directory helper: '.$helper_name.EXT);   
        }
        
        if(file_exists(DIR.$GLOBALS['d'].DS.'helpers'.DS.$helper.EXT))
        {
            include(DIR.$GLOBALS['d'].DS.'helpers'.DS.$helper.EXT); 
            return;
        }  
         
        throw new LoaderException('Unable to locate the directory helper: '.$helper.EXT); 
    }   
    
    /**
    * loader::base_helper();
    *
    * @return   void
    */
    public static function base_helper($helper)
    {
        if(file_exists(BASE.'helpers'.DS.$helper.EXT)) 
        { 
            include(BASE.'helpers'.DS.$helper.EXT); 
            return; 
        }
        
        throw new LoaderException('Unable to locate the base helper: '.$helper. EXT);
    }
    
    /**
    * loader::user_helper();
    * Load user 'class' helpers
    * 
    * @return void
    */
    public function user_helper($helper)
    {
        if(class_exists($helper))
        throw new LoaderException('This user helper loaded before !');
        
        if(file_exists(APP.'user'.DS.'helpers'.DS.$helper.EXT)) 
        { 
            include(APP.'user'.DS.'helpers'.DS.$helper.EXT); 
            return; 
        }
        
        throw new LoaderException('Unable to locate the user helper: '.$helper. EXT);   
    } 
        
    /**
    * Loads a language file from /application dir
    *
    * @access   public
    * @param    array
    * @param    string
    * @return   void
    */
    public static function app_lang($file = '', $folder = '', $return = FALSE)
    {
        obullo::instance()->lang->load($file, $folder, FALSE, $return);
    }
            
    /**
    * Loads a language file from /base dir
    *
    * @access   public
    * @param    array
    * @param    string
    * @return   void
    */
    public static function base_lang($file = '', $folder = '', $return = FALSE)
    {
        obullo::instance()->lang->load($file, $folder, TRUE ,$return);
    }
    
    /**
    * Loads a config file
    *
    * @access   public
    * @param    array
    * @return   void
    */                                 
    public static function config($file)    
    {
        obullo::instance()->config->load($file);
    }
                          
    /**
    * Load directly PEAR libraries.
    * 
    * @author   Ersin Güvenç
    * @author   you..    
    * @param    string e.g. 'Class', 'Mail/mime', 'Spreadsheet/Excel/Writer'
    * @version  0.1
    * @return   boolean
    */
    public static function pear($class)
    {
        if(file_exists($class)) { require($class . EXT); return; }
        
        throw new LoaderException('Unable to locate the pear library:'. $class . EXT);
    }
        
    /**
    * Build js files in <head> tags
    * 
    * @author   Ersin Güvenç
    * @param    string $path
    * @param    string $filename
    * @param    string $arguments add argument ?arg=1&arg2=2
    * @param    boolean $compression
    * @return   string
    */
    public function source_js($filename, $arguments = '')
    {           
        $content = base_register('Content');
        
        return $content->js($filename, $arguments, 'source');
    }
    
    /**
    * loader::js() load script
    * from directory folder
    * 
    * @param mixed $filename
    * @param mixed $arguments
    */
    public function js($filename, $arguments = '')
    {
        $content = base_register('Content');
        
        return $content->js($filename, $arguments, 'directory');
    }

    /**
    * loader::base_script();
    * 
    * load base java script files
    * 
    * @param    string $filename
    * @param    array $data
    */
    public function script($filename, $data = array())
    {
        $content = base_register('Content');
        
        return $content->script(DIR . $GLOBALS['d'] . DS . 'scripts' . DS, $filename, $data);
    }
    
    /**
    * loader::app_script();
    * 
    * load application java script files
    * 
    * @param    string $filename
    * @param    array $data
    */
    public function app_script($filename, $data = array())
    {
        $content = base_register('Content');
        
        return $content->script(APP . 'scripts' . DS, $filename, $data);
    }
    
    /**
    * loader::base_script();
    * 
    * load base java script files
    * 
    * @param    string $filename
    * @param    array $data
    */
    public function base_script($filename, $data = array())
    {        
        $content = base_register('Content');
        
        return $content->script(BASE . 'scripts' . DS, $filename, $data);
    }
    
    /**
    * loader::css();
    * 
    * load directory css script files
    * 
    * @param    mixed   $filename
    * @param    string  $media 'all' or 'print' etc..
    * @param    string  $arguments
    */
    public function css($filename, $media = 'all', $arguments = '')
    {
        $content = base_register('Content');
        
        return $content->css($filename, $media, $arguments, 'directory');  
    }
    
    /**
    * loader::source_css();
    * 
    * load css script files from /sources
    * 
    * @param    mixed   $filename
    * @param    string  $media 'all' or 'print' etc..
    * @param    string  $arguments
    */
    public function source_css($filename, $media = 'all', $arguments = '')
    {
        $content = base_register('Content');
        
        return $content->css($filename, $media, $arguments, 'source');
    }
    
    // @ Support for loader::libray() inside from public model functions 
    // If you declare a library like this loader::library(); 
    // from model __construct() function, it works this is ok
    // because loader::model() function already loads it via $OB->$model_name->_asn_lib();
    // but when u declare it inside a model function it will not work
    // so you will get an error: Undefined property: Model_test::$myclass
    // This function fix the problem, assigns all library files to model. (Ersin) 

    private static function asn_to_models()
    {
        $OB = obullo::instance();
        
        if (count($OB->_mods) == 0) return;
        
        foreach ($OB->_mods as $model_name=>$val)
        $OB->$model_name->_asn_lib();
    }
 

} //end of the class.

          
?>
